Part Number Hot Search : 
IW0140A4 KPC825 UTC2822H L4812 3K7002 D5025 A330MC BYD57VA
Product Description
Full Text Search
 

To Download AN1198 Datasheet File

  If you can't view the Datasheet, Please click here to try to view without PDF Reader .  
 
 


  Datasheet File OCR Text:
  1/46 february 2001 AN1198 application note software drivers for the m29f160b, m29w160b and m29w160d flash memories contents n introduction n the m29f160b programming model n writing c code for the m29f160b n c library functions provided n porting the drivers to the target system n limitations of the software n conclusion n revision history n c1198_16.h listing n c1198_16.c listing n c1198_08.h listing n c1198_08.c listing introduction this application note provides library source code in c for the m29f160b, the m29w160b and the m29w160d flash memo- ries. the m29w160b, with a rated power supply of 3v, is a low voltage version of the m29f160b whose power supply is rated at 5v. the features of the m29w160d are identical to the m29w160b but it is made in 0.18 m technology. this application note supports all three devices and all technical information about the m29f160b also applies to the m29w160b and m29w160d, except where otherwise specified. there are two different m29f160b parts, the m29f160bt and the m29f160bb, which will be referred to generically as the m29f160b. similarly the term m29w160b in this application note can refer to either the m29w160bt or the m29w160bb; the term m29w160d can refer to either the m29w160dt or the m29w160db. listings of the source code can be found at the end of this doc- ument. the source code is also available in file form from the internet site http://www.st.com or from your stmicroelectronics distributor. the c1198_16.c and c1198_16.h files contain librar- ies for accessing the m29f160b and the m29w160b flash memories in 16-bit bus mode, whereas the c1198_08.c and c1198_08.h files contain the 8-bit drivers for these devices. also included in this application note is an overview of the pro- gramming model for the m29f160b, m29w160b and m29w160d. this will familiarize the reader with the operation of the memory devices and provide a basis for understanding and modifying the accompanying source code. the source code is written to be as platform independent as possible and requires minimal changes by the user in order to compile and run. the application note explains how the user should modify the source code for their individual target hard- ware. all of the source code is backed up by comments explain- ing how it is used and why it has been written as it has. this application note does not replace the m29f160b data sheet. it refers to the data sheet throughout and it is necessary to have a copy in order to follow some of the explanations. the software and accompanying documentation has been fully tested on a target platform. it is small in size and can be applied to any target hardware.
AN1198 - application note 2/46 the am29f160d and am29lv160d from amd are software and hardware compatible with the m29f160b and m29w160b/m29w160d respectively. source code written to use amds am29f160d and am29lv160d can easily be modified to use stmicroelectronicss m29f160b and m29w160b/ m29w160d instead (see stmicroelectronics application note an1185 for more details). the m29f160b programming model the m29f160b is a 16mb (2mb x8 or 1mb x16) flash memory which can be electrically erased and pro- grammed through special coded command sequences on most standard microprocessor buses. the de- vice is broken down into 35 blocks of varying sizes. each block can be erased individually, or the whole chip can be erased at once, erasing all 16mb. the m29f160b is a single voltage device. it differs from first generation devices which require a 12v sup- ply to program or erase. the m29f160b is therefore easier to use since the hardware does not need to cater for special bus signal levels. the voltages needed to erase the device are generated by charge pumps inside the device. included in the device is a program/erase controller. with first generation flash memory devices the soft- ware had to manually program all of the bytes to 00h before erasing to ffh using special programming sequences. the program/erase controller in the m29f160b allows a simpler programming model to be used, by taking care of all the necessary steps required to erase and program the memory. this has led to improved reliability so that in excess of 100,000 program/erase cycles are guaranteed per block on the device. the m29f160b does, however, require some high voltage bus signals if all of the functionality of the de- vice is to be accessed. each block can be protected against accidental programming or erasure. protect- ing and unprotecting the blocks requires v id (about 12v) on some of the pins. most applications of the device will not include these functions. however, blocks may be pre-programmed, protected and unpro- tected by an eprom programmer prior to fitting into the hardware. unprotected blocks may still be used to store data and parameters. by protecting a block, accidental data loss through software failure cannot occur. bus operations and commands most of the functionality of the m29f160b is available via the two standard bus operations: read and write. read operations retrieve data or status information from the device. write operations are interpreted by the device as commands, which modify the data stored or the behavior of the device. only certain special sequences of write operations are recognized as commands by the m29f160b. the various commands recognized by the m29f160b are listed in the commands table of the datasheet and can be grouped as follows: 1. read/reset 2. auto select 3. erase 4. program 5. erase suspend the read/reset command returns the m29f160b to its reset state where it behaves as a rom. in this state, a read operation outputs onto the data bus the data stored at the specified address of the device. the auto select command places the device in the auto select mode, which allows the user to read the electronic signature and block protection status of the device. the electronic signature (manufacturer and device codes) and the block protection status are accessed by reading different addresses whilst in the auto select mode.
3/46 AN1198 - application note the erase commands are used to set all the bits to 1 in every memory location in the selected blocks (block erase command) or in the whole chip (chip erase command). all data previously stored in the erased blocks will be lost. the erase commands take longer to execute than the other commands, be- cause entire blocks are erased at a time. the program command is used to modify the data stored at the specified address of the device. note that programming cannot change bits from 0 to 1. it may therefore be necessary to erase the block before programming to addresses within it. programming modifies a single word/byte at a time. programming larger amounts of data must be done one word/byte at a time, by issuing a program command, waiting for the command to complete, then issuing the next program command, and so on. each program command requires 4 write operations to issue. however, after issuing the unlock bypass command, program com- mands only require 2 write operations. using unlock bypass will thus save some time when a large num- ber of addresses need to be programmed at a time. issuing the erase suspend command during a block erase operation will temporarily place the m29f160b in erase suspend mode. in this mode the blocks not being erased may be read or programmed as if in the reset state of the device. this allows the user to access information stored in the device immediately rather than waiting until the block erase operation completes, typically 0.6s for the m29f160b or 0.8s for the m29w160b/m29w160d. the block erase operation is resumed when the device receives the erase resume command. the status register while the m29f160b is programming or erasing, a read from the device will output the status register of the program/erase controller. this provides valuable information about the current program or erase command. the status register bits are described in the status register bits table of the m29f160b data sheet. their main use is to determine when programming or erasing is complete and whether it is suc- cessful or not. completion of the program or erase operation can be determined either from the polling bit (status reg- ister bit dq7) or from the toggle bit (status register bit dq6), by following the data polling flow chart figure or the data toggle flow chart figure in the datasheet. the library routines described in this appli- cation note use the data toggle flow chart. however, a function based on the data polling flow chart is also provided as an illustration. programming or erasing errors are indicated by the error bit (status register bit dq5) becoming 1 before the command has completed. if a failure occurs, the command will not complete and read operations will continue to output the status register bits until a read/reset command is issued to the device. a detailed example the commands table of the m29f160b data sheet describes the sequences of bus write operations that will be recognized by the program/erase controller as valid commands. for example programming 9465h to the address 03e2h in 16-bit bus mode requires the user to write the following sequence (in c): *(unsigned int*)(0x0555) = 0x00aa; *(unsigned int*)(0x02aa) = 0x0055; *(unsigned int*)(0x0555) = 0x00a0; *(unsigned int*)(0x03e2) = 0x9465; in 8-bit bus mode writing 65h to address 07c4h would require: *(unsigned char*)(0x0aaa) = 0xaa; *(unsigned char*)(0x0555) = 0x55; *(unsigned char*)(0x0aaa) = 0xa0; *(unsigned char*)(0x07c4) = 0x65;
AN1198 - application note 4/46 note that, due to the organization of the address bus and data bus, this example writes 65h to the same address for both 16-bit and 8-bit bus modes. the internal organization of the m29f160b is such that the lsb of the 16-bit mode is stored at the lower address of the 8-bit mode. this example assumes that address 0000h of the m29f160b is mapped to address 0000h in the micro- processor address space. in practice it is likely that the flash will have a base offset which needs to be added to the address. while the device is programming the specified address, read operations will access the status register bits. status register bit dq5 will be 1 if an error has occurred. bit dq6 will toggle while programming is on-going. bit dq7 will be the complement of the data being programmed. there are only two possible outcomes to this programming command: success or failure. success will be indicated by the toggle bit dq6 no longer toggling but being constant at its programmed value (of 1 in our example) and the polling bit dq7 also being at its programmed value (of 0 in our example). failure will be indicated by the error bit dq5 becoming 1 while the toggle bit dq6 still toggles and the polling bit dq7 remains the complement (1 in our example) of the data being programmed. note that failure of the device itself is extremely unlikely. if the command fails it will normally be because the user is attempting to change a 0 to a 1 by programming. it is only possible to change a 0 to a 1 by erasing. writing c code for the m29f160b the low-level functions (drivers) described in this application note have been provided to simplify the pro- cess of developing application code in c for the stmicroelectronics flash memories (m29f160b, m29w160b and m29w160d). this enables users to concentrate on writing the high level functions re- quired for their particular applications. these high level functions can access the flash memories by call- ing the low level drivers, hence keeping details of special command sequences away from the users' high level code: this will result in source code both simpler and easier to maintain. code developed using the drivers provided can be decomposed into three layers: 1. the hardware specific bus operations 2. the low-level drivers 3. the high level functions written by the user the implementation in c of the hardware specific read and write bus operations is required by the low- level drivers in order to communicate with the m29f160b. this implementation is hardware platform de- pendent as it is affected by which microprocessor the c code runs on and by where in the microproces- sor's address space the memory device is located. the user will have to write the c functions appropriate to his hardware platform (see flashread() and flashwrite() in the next section). the low-level drivers take care of issuing the correct sequences of write operations for each command and of interpreting the information received from the device during programming or erasing. these drivers encode all the specific details of how to issue commands and how to interpret the status register bits. the high level functions written by the user will access the memory device by calling the low-level func- tions. by keeping the specific details of how to access the m29f160b away from the high level functions, the user is left with code which is simple and easier to maintain. it also makes the user's high level func- tions easier to apply to other stmicroelectronics flash memories. when developing an application, the user is advised to proceed as follows: C first write a simple program to test the low level drivers provided and verify that these operate as ex- pected on the user's target hardware and software environments. C then the user should write the high level code for his application, which will access the flash memories by calling the low level drivers provided. C finally test the complete application source code thoroughly.
5/46 AN1198 - application note c library functions provided the software library provided with this application note provides the user with source code for the following functions: flashreadreset() is used to reset the device into the read mode. note that there should be no need to call this function under normal operation as all of the other software library functions leave the device in this mode. flashautoselect() is used to identify the manufacturer code, device code and the block protection status of the device. flashblockerase() is used to erase one or more blocks in the device. multiple blocks will be erased simultaneously to reduce the overall erase time. this function checks that none of the blocks specified are protected and does not erase any blocks if some of the specified blocks are protected. flashchiperase() is used to erase the entire chip. it will not erase any blo cks if there is a protected block on the chip. flashprogram() is used to program data arrays into the flash. only previously erased words/bytes can be programmed reliably. the function will not program any data if any of the words/bytes in the array fall inside a protected block. the functions provided in the software library rely on the user implementing the hardware specific bus op- erations as well as a suitable timing function. this is to be done by writing three functions as follows: C flashread() must be written to read a value from the flash. C flashwrite() must be written to write a value to the flash. C flashpause() must be written to provide a timer with microsecond resolution. this is used to wait while the flash recovers from some conditions. an example of these functions is provided in the source code. in many instances these functions can be written as macros and therefore will not incur the function call time overhead. the two functions which perform the basic i/o to the device have been provided for users who have awkward systems. for example where the addressing system is peculiar or the data bus has d0..d7 of the device on d8..d15 of the microprocessor. they allow any user to quickly adapt the code to virtually any target system. throughout the functions assumptions have been made on the data types. these are: a char is 8 bits (1 byte). this is not the case in all microcontrollers. where it is not it will be necessary to mask the unused bits of the word (particularly in the user's 8-bit mode flashread() function). an int is 16 bits (2 bytes). again, like the char , if this is not the case it will be necessary to use a variable type which is 16 bits or longer and mask bits above 16 bits (for example in the users 16-bit mode flashread() function). a long is 32 bits (4 bytes). it is necessary to have arithmetic greater than 16 bits in order to address the entire device. two approaches to the addressing are available: the desired address in the flash can be specified by a 32 bit linear pointer or a 32 bit offset into the device could be provided by the user. the 16-bit bus mode flashread() functions in each case would declared as: unsigned int flashread( unsigned int *addr); unsigned int flashread( unsigned long uloff); the pointer option has the advantage that it runs faster. the 32 bit offset needs to be changed to an ad- dress for each access and this involves 32 bit arithmetic. using a 32 bit offset is, however, more portable since the resulting software can easily be changed to run on microprocessors with segmented memory spaces (such as the 8086). for maximum portability all the functions in this application note use a 32 bit unsigned long offset, rather than a pointer.
AN1198 - application note 6/46 porting the drivers to the target system before using the software in the target system the user needs to do the following: 1. define use_m29f160bt , use_m29f160bb , use_m29w160bt , use_m29w160bb , use_m29w160dt , or use_m29w160db depending on whether an m29f160bt, m29f160bb, m29w160bt, m29w160bb, m29w160dt or an m29w160db is fitted. the top of the source file provided defines use_m29f160bt as an example. 2. write flashread() , flashwrite() and flashpause() functions appropriate to the target hard- ware. 3. search through the code for the /* dsi */ and /* eni */ comments and disable/enable interrupts at the appropriate points. the example flashread() and flashwrite() functions provided in the source code should give the user a good idea of what is required and can be used in many instances without much modification. to test the source code in the target system start by simply reading from the m29f160b. if it is erased then only ffh data should be read. next read the manufacturer and device codes and check they are correct. if these functions work then it is likely that all of the functions will work but they should all be tested thoroughly. the programmer needs to take extra care when the device is accessed during an interrupt service routine. three situations exist which must be considered: 1. when the device is in read mode interrupts can freely read from the device. 2. interrupts which do not access the device may be used during the program, autoselect and chip erase functions. 3. during the time critical section of the block erase function interrupts are not permitted. an interrupt dur- ing this time may cause a time-out and result in some of the blocks not being erased correctly. the programmer should also take care when a reset is applied during program or erase operations. the flash will be left in an indeterminate state and data could be lost. c does not provide a standard library function for disabling interrupts. furthermore different applications have different tolerances on when interrupts may be disabled. therefore no protection from the misuse of interrupts could be incorporated into the library source code. it is strongly recommended that the user dis- ables interrupts where the /* dsi */ comments are placed in the source code. if this is not possible then the user should erase one block at a time. limitations of the software the software provided does not implement a full set of the m29f160b's functionality. it is left to the user to implement the erase suspend and unlock bypass commands of the device. the standby mode is a hardware feature of the device and cannot be controlled through software. care should be taken in some of the while() loops. no time-outs have been implemented. software ex- ecution may stop in one of the loops due to a hardware error. a /* timeout! */ comment has been put at these places and the user can add a timer to them to prevent the software failing. the software only caters for one device in the system. to add software for more devices a mechanism for selecting the devices will be required. when an error occurs the software simply returns the error message. it is left to the user to decide what to do. either the command can be tried again or, if necessary the device may need to be replaced. conclusion the m29f160b, m29w160b and m29w160d single voltage flash memories are ideal products for em- bedded and other computer systems, able to be easily interfaced to microprocessors and driven with sim- ple software drivers written in the c language.
7/46 AN1198 - application note revision history table 1. document revision history date version revision details september 1999 -01 first issue. february 2001 -02 updated document and c code to include the m29w160d flash memories. there are no additional features added to the c code; c code retested using m29w160d parts.
AN1198 - application note 8/46 /****c1198_08.h*header file for c1198_08.c************************************** filename: c1198_08.h description: header file for c1198_08.c. consult the c file for details copyright (c) 2001 stmicroelectronics. this program is provided as is without warranty of any kind,either expressed or implied, including but not limited to, the implied warranty of merchantability and fitness for a particular purpose. the entire risk as to the quality and performance of the program is with you. should the program prove defective, you assume the cost of all necessary servicing, repair or correction. *******************************************************************************/ /******************************************************************************* commands for the various functions *******************************************************************************/ #define flash_read_manufacturer (-2) #define flash_read_device_code (-1) /******************************************************************************* error conditions and return values. see end of c file for explanations and help *******************************************************************************/ #define flash_block_protected (0x01) #define flash_block_unprotected (0x00) #define flash_block_not_erased (0xff) #define flash_block_erase_failure (0xfe) #define flash_block_erased (0xfd) #define flash_success (-1) #define flash_poll_fail (-2) #define flash_too_many_blocks (-3) #define flash_mpu_too_slow (-4) #define flash_block_invalid (-5) #define flash_program_fail (-6) #define flash_offset_out_of_range (-7) #define flash_wrong_type (-8) #define flash_block_failed_erase (-9) #define flash_erase_fail (-14) #define flash_toggle_fail (-15) /******************************************************************************* function prototypes *******************************************************************************/ extern unsigned char flashread( unsigned long uloff ); extern void flashreadreset( void ); extern int flashautoselect( int ifunc ); extern int flashblockerase( unsigned char ucnumblocks, unsigned char ucblock[]); extern int flashchiperase( unsigned char *ucresults ); extern int flashprogram( unsigned long uloff, size_t numbytes, void *array ); extern char *flasherrorstr( int ierrnum );
9/46 AN1198 - application note /****c1198_08.c*16mb flash memory*********************************************** filename: c1198_08.c description: library routines for m29f160b, m29w160b, and m29w160d 16mb (2mb x8) flash memories. 8 bit driver. revision: 1.01 date: 07/02/01 author: tim webster, oxford technical solutions (www.ots.ndirect.co.uk) copyright (c) 2001 stmicroelectronics. this program is provided as is without warranty of any kind, either expressed or implied, including but not limited to, the implied warranty of merchantability and fitness for a particular purpose. the entire risk as to the quality and performance of the program is with you. should the program prove defective, you assume the cost of all necessary servicing, repair or correction. ******************************************************************************** version history. ver. date comments 1.00 29/09/99 initial release of the software. 1.01 07/02/01 added support for m29w160d parts. ******************************************************************************** this source file provides library c code for using the m29x160b devices. the following devices are supported in the code: m29f160bt m29f160bb m29w160bt m29w160bb m29w160dt m29w160db this file is used to access the devices in 8-bit mode only. a separate file is available for users who wish to access the device in 16 bit mode (c1198_16.c). the following functions are available in this library: flashreadreset() to reset the flash for normal memory access flashautoselect() to get information about the device flashblockerase() to erase one or more blocks flashchiperase() to erase the whole chip flashprogram() to program a byte or an array flasherrorstr() to return the error string of an error for further information consult the data sheet and the application note. the application note gives information about how to modify this code for a specific application. the hardware specific functions which need to be modified by the user are: flashwrite() for writing a byte to the flash flashread() for reading a byte from the flash
AN1198 - application note 10/46 flashpause() for timing short pauses (in micro seconds) a list of the error conditions is given at the end of the code. there are no timeouts implemented in the loops in the code. at each point where an infinite loop is implemented a comment /# timeout! #/ has been placed. it is up to the user to implement these to avoid the code hanging instead of timing out. since c does not include a method for disabling interrupts to keep time- critical sections of code from being disabled. the user may wish to disable interrupt during parts of the code to avoid the flash_mpu_too_slow error from occuring if an interrupt occurs at the wrong time. where interrupt should be disabled and re-enabled there is a /# dsi! #/ or /# eni! #/ comment. the source code assumes that the compiler implements the numerical types as unsigned char 8 bits unsigned int 16 bits unsigned long 32 bits additional changes to the code will be necessary if these are not correct. *******************************************************************************/ #include #include c1198_08.h /* header file with global prototypes */ #define use_m29f160bt /******************************************************************************* constants *******************************************************************************/ #define counts_per_microsecond (200) #define manufacturer_st (0x20) /* manufacturer code */ #define base_addr ((volatile unsigned char*)0x0000) /* base_addr is the base address of the flash, see the functions flashread() and flashwrite(). some applications which require a more complicated flashread() or flashwrite() may not use base_addr */ #define any_addr (0x0000l) /* any address offset within the flash memory will do */ #ifdef use_m29f160bt #define expected_device (0xcc) /* device code for the m29f160bt */ #endif #ifdef use_m29f160bb #define expected_device (0x4b) /* device code for the m29f160bb */ #endif #ifdef use_m29w160bt #define expected_device (0xc4) /* device code for the m29w160bt */ #endif #ifdef use_m29w160bb #define expected_device (0x49) /* device code for the m29w160bb */ #endif
11/46 AN1198 - application note #ifdef use_m29w160dt #define expected_device (0xc4) /* device code for the m29w160dt */ #endif #ifdef use_m29w160db #define expected_device (0x49) /* device code for the m29w160db */ #endif #if defined(use_m29f160bt) | defined(use_m29w160bt) | defined(use_m29w160dt) /* block organisation for top boot block devices */ static const unsigned long blockoffset[] = { 0x000000l, /* start offset of block 0 */ 0x010000l, /* start offset of block 1 */ 0x020000l, /* start offset of block 2 */ 0x030000l, /* start offset of block 3 */ 0x040000l, /* start offset of block 4 */ 0x050000l, /* start offset of block 5 */ 0x060000l, /* start offset of block 6 */ 0x070000l, /* start offset of block 7 */ 0x080000l, /* start offset of block 8 */ 0x090000l, /* start offset of block 9 */ 0x0a0000l, /* start offset of block 10 */ 0x0b0000l, /* start offset of block 11 */ 0x0c0000l, /* start offset of block 12 */ 0x0d0000l, /* start offset of block 13 */ 0x0e0000l, /* start offset of block 14 */ 0x0f0000l, /* start offset of block 15 */ 0x100000l, /* start offset of block 16 */ 0x110000l, /* start offset of block 17 */ 0x120000l, /* start offset of block 18 */ 0x130000l, /* start offset of block 19 */ 0x140000l, /* start offset of block 20 */ 0x150000l, /* start offset of block 21 */ 0x160000l, /* start offset of block 22 */ 0x170000l, /* start offset of block 23 */ 0x180000l, /* start offset of block 24 */ 0x190000l, /* start offset of block 25 */ 0x1a0000l, /* start offset of block 26 */ 0x1b0000l, /* start offset of block 27 */ 0x1c0000l, /* start offset of block 28 */ 0x1d0000l, /* start offset of block 29 */ 0x1e0000l, /* start offset of block 30 */ 0x1f0000l, /* start offset of block 31 */ 0x1f8000l, /* start offset of block 32 */ 0x1fa000l, /* start offset of block 33 */ 0x1fc000l /* start offset of block 34 */ }; #endif /* defined(use_m29f160bt) | defined(use_m29w160bt) | defined(use_m29w160dt) */ #if defined(use_m29f160bb) | defined(use_m29w160bb) | defined(use_m29w160db) /* block organisation for bottom boot block devices */ static const unsigned long blockoffset[] = { 0x000000l, /* start offset of block 0 */ 0x004000l, /* start offset of block 1 */ 0x006000l, /* start offset of block 2 */ 0x008000l, /* start offset of block 3 */
AN1198 - application note 12/46 0x010000l, /* start offset of block 4 */ 0x020000l, /* start offset of block 5 */ 0x030000l, /* start offset of block 6 */ 0x040000l, /* start offset of block 7 */ 0x050000l, /* start offset of block 8 */ 0x060000l, /* start offset of block 9 */ 0x070000l, /* start offset of block 10 */ 0x080000l, /* start offset of block 11 */ 0x090000l, /* start offset of block 12 */ 0x0a0000l, /* start offset of block 13 */ 0x0b0000l, /* start offset of block 14 */ 0x0c0000l, /* start offset of block 15 */ 0x0d0000l, /* start offset of block 16 */ 0x0e0000l, /* start offset of block 17 */ 0x0f0000l, /* start offset of block 18 */ 0x100000l, /* start offset of block 19 */ 0x110000l, /* start offset of block 20 */ 0x120000l, /* start offset of block 21 */ 0x130000l, /* start offset of block 22 */ 0x140000l, /* start offset of block 23 */ 0x150000l, /* start offset of block 24 */ 0x160000l, /* start offset of block 25 */ 0x170000l, /* start offset of block 26 */ 0x180000l, /* start offset of block 27 */ 0x190000l, /* start offset of block 28 */ 0x1a0000l, /* start offset of block 29 */ 0x1b0000l, /* start offset of block 30 */ 0x1c0000l, /* start offset of block 31 */ 0x1d0000l, /* start offset of block 32 */ 0x1e0000l, /* start offset of block 33 */ 0x1f0000l /* start offset of block 34 */ }; #endif /* defined(use_m29f160bb) | defined(use_m29w160bb) | defined(use_m29w160db) */ #define num_blocks (sizeof(blockoffset)/sizeof(blockoffset[0])) #define flash_size (0x200000l) /* 2m */ /******************************************************************************* static prototypes the following functions are only needed in this module. *******************************************************************************/ static unsigned char flashwrite( unsigned long uloff, unsigned char ucval ); static void flashpause( unsigned int umicroseconds ); static int flashdatatoggle( void ); static int flashblockfailederase( unsigned char ucblock ); /****************************************************************************** the function flashdatapoll() declared below is not used by this library but is provided as an illustration of the data polling flow chart *******************************************************************************/ #define illustration_only #ifndef illustration_only static int flashdatapoll( unsigned long uloff, unsigned char ucval ); #endif /* !illustration_only */
13/46 AN1198 - application note /******************************************************************************* function: unsigned char flashwrite( unsigned long uloff, unsigned char ucval) arguments: uloff is the byte offset in the flash to write to ucval is the value to be written returns: ucval description: this function is used to write a byte to the flash. on many microprocessor systems a macro can be used instead, increasing the speed of the flash routines. for example: #define flashwrite( uloff, ucval ) ( base_addr[uloff] = (unsigned char) ucval ) a function is used here instead to allow the user to expand it if necessary. the function is made to return ucval so that it is compatible with the macro. pseudo code: step 1: write ucval to the byte offset in the flash step 2: return ucval *******************************************************************************/ static unsigned char flashwrite( unsigned long uloff, unsigned char ucval ) { /* step1, 2: write ucval to the byte offset in the flash and return it */ return base_addr[uloff] = ucval; } /******************************************************************************* function: unsigned char flashread( unsigned long uloff ) arguments: uloff is the byte offset into the flash to read from returns: the unsigned char at the byte offset description: this function is used to read a byte from the flash. on many microprocessor systems a macro can be used instead, increasing the speed of the flash routines. for example: #define flashread( uloff ) ( base_addr[uloff] ) a function is used here instead to allow the user to expand it if necessary. pseudo code: step 1: return the value at byte offset uloff *******************************************************************************/ unsigned char flashread( unsigned long uloff ) { /* step 1 return the value at byte offset uloff */ return base_addr[uloff]; } /******************************************************************************* function: void flashpause( unsigned int umicroseconds ) arguments: umicroseconds is the length of the pause in microseconds returns: none description: this routine returns after umicroseconds have elapsed. it is used in several parts of the code to generate a pause required for correct operation of the flash part. the routine here works by counting. the user may already have a more suitable routine for timing which can be used. pseudo code: step 1: compute count size for pause. step 2: count to the required size.
AN1198 - application note 14/46 *******************************************************************************/ static void flashpause( unsigned int umicroseconds ) { volatile unsigned long ulcountsize; /* step 1: compute the count size */ ulcountsize = (unsigned long)umicroseconds * counts_per_microsecond; /* step 2: count to the required size */ while( ulcountsize > 0 ) /* test to see if finished */ ulcountsize--; /* and count down */ } /******************************************************************************* function: void flashreadreset( void ) arguments: none return value: none description: this function places the flash in the read mode described in the data sheet. in this mode the flash can be read as normal memory. all of the other functions leave the flash in the read mode so this is not strictly necessary. it is provided for completeness. note: a wait of 10us is required if the command is called during a program or erase instruction. this is included here to guarantee correct operation. the functions in this library call this function if they suspect an error during programming or erasing so that the 10us pause is included. otherwise they use the single instruction technique for increased speed. pseudo code: step 1: write command sequence (see commands table of the data sheet) step 2: wait 10us *******************************************************************************/ void flashreadreset( void ) { /* step 1: write command sequence */ flashwrite( 0x0aaal, 0xaa ); /* 1st cycle */ flashwrite( 0x0555l, 0x55 ); /* 2nd cycle */ flashwrite( any_addr, 0xf0 ); /* 3rd cycle: write 0xf0 to any address */ /* step 2: wait 10us */ flashpause( 10 ); } /******************************************************************************* function: int flashautoselect( int ifunc ) arguments: ifunc should be set either to the read signature values or to the block number. the header file defines the values for reading the signature. note: the first block is block 0 return value: when ifunc is >= 0 the function returns flash_block_protected (01h) if the block is protected and flash_block_unprotected (00h) if it is unprotected. see the auto select command in the data sheet for further information. when ifunc is flash_read_manufacturer (-2) the function returns the manufacturers code. the manufacturer code for st is 20h.
15/46 AN1198 - application note when ifunc is flash_read_device_code (-1) the function returns the device code. the device codes for the parts are: m29f160bt cch m29f160bb 4bh m29w160bt c4h m29w160bb 49h m29w160dt c4h m29w160db 49h when ifunc is invalid the function returns flash_block_invalid (-5) description: this function can be used to read the electronic signature of the device, the manufacturer code or the protection level of a block. pseudo code: step 1: send the auto select command to the device step 2: read the required function from the device. step 3: return the device to read mode. *******************************************************************************/ int flashautoselect( int ifunc ) { int iretval; /* holds the return value */ /* step 1: send the auto select command */ flashwrite( 0x0aaal, 0xaa ); /* 1st cycle */ flashwrite( 0x0555l, 0x55 ); /* 2nd cycle */ flashwrite( 0x0aaal, 0x90 ); /* 3rd cycle */ /* step 2: read the required function */ if( ifunc == flash_read_manufacturer ) iretval = (int) flashread( 0x0000l ); /* a0 = a1 = 0 */ else if( ifunc == flash_read_device_code ) iretval = (int) flashread( 0x0002l ); /* a0 = 1, a1 = 0, remember a-1 */ else if( (ifunc >= 0) && (ifunc < num_blocks) ) iretval = flashread( blockoffset[ifunc] + 0x0004l ); /* a0 = 0, a1 = 1, remember a-1 */ else iretval = flash_block_invalid; /* step 3: return to read mode */ flashwrite( any_addr, 0xf0 ); /* use single instruction cycle method */ return iretval; } /******************************************************************************* function: int flashblockerase( unsigned char ucnumblocks, unsigned char ucblock[] ) arguments: ucnumblocks holds the number of blocks in the array ucblock ucblock is an array containing the blocks to be erased. return value: the function returns the following conditions: flash_success (-1) flash_too_many_blocks (-3) flash_mpu_too_slow (-4) flash_wrong_type (-8)
AN1198 - application note 16/46 flash_erase_fail (-14) number of the first protected or invalid block the users array, ucblock[] is used to report errors on the specified blocks. if a time-out occurs because the mpu is too slow then the blocks in ucblocks which are not erased are overwritten with flash_block_not_erased (ffh) and the function returns flash_mpu_too_slow. if an error occurs during the erasing of the blocks the function returns flash_erase_fail. if both errors occur then the function will set the ucblock array to flash_block_not_erased for the unerased blocks. it will return flash_erase_fail even though the flash_mpu_too_slow has also occurred. description: this function erases up to ucnumblocks in the flash. the blocks can be listed in any order. the function does not return until the blocks are erased. if any blocks are protected or invalid none of the blocks are erased. during the erase cycle the data toggle flow chart of the data sheet is followed. the polling bit, dq7, is not used. pseudo code: step 1: check for correct flash type step 2: check for protected or invalid blocks step 3: write block erase command step 4: check for time-out blocks step 5: wait for the timer bit to be set. step 6: follow data toggle flow chart until program/erase controller has completed step 7: return to read mode (if an error occurred) *******************************************************************************/ int flashblockerase( unsigned char ucnumblocks, unsigned char ucblock[] ) { unsigned char uccurblock; /* range variable to track current block */ int iretval = flash_success; /* holds return value: optimistic initially! */ unsigned char ucfirstread, ucsecondread; /* used to check toggle bit dq2 */ /* step 1: check for correct flash type */ if( !(flashautoselect( flash_read_manufacturer ) == manufacturer_st) || !(flashautoselect( flash_read_device_code ) == expected_device ) ) return flash_wrong_type; /* step 2: check for protected or invalid blocks. */ if( ucnumblocks > num_blocks ) /* check specified blocks <= num_blocks */ return flash_too_many_blocks; for( uccurblock = 0; uccurblock < ucnumblocks; uccurblock++ ) { /* use flashautoselect to find protected or invalid blocks */ if( flashautoselect((int)ucblock[uccurblock]) != flash_block_unprotected ) return (int)ucblock[uccurblock]; /* return protected/invalid blocks */ } /* step 3: write block erase command */ flashwrite( 0x0aaal, 0xaa ); flashwrite( 0x0555l, 0x55 ); flashwrite( 0x0aaal, 0x80 ); flashwrite( 0x0aaal, 0xaa ); flashwrite( 0x0555l, 0x55 ); /* dsi!: time critical section. additional blocks must be added every 50us */
17/46 AN1198 - application note for( uccurblock = 0; uccurblock < ucnumblocks; uccurblock++ ) { flashwrite( blockoffset[ucblock[uccurblock]], 0x30 ); /* check for erase timeout period (is bit dq3 set?) */ if( (flashread( blockoffset[ucblock[0]] ) & 0x08) == 0x08 ) break; /* cannot set any more blocks due to timeout */ } /* eni! */ /* step 4: check for time-out blocks */ /* if timeout occurred then check if current block is erasing or not */ /* use dq2 of status register, toggle implies block is erasing */ if( uccurblock < ucnumblocks ) { ucfirstread = flashread( blockoffset[ucblock[uccurblock]] ) & 0x04; ucsecondread = flashread( blockoffset[ucblock[uccurblock]] ) & 0x04; if( ucfirstread != ucsecondread ) { uccurblock++; /* point to the next block */ } if( uccurblock < ucnumblocks ) { /* indicate that some blocks have been timed out of the erase list */ iretval = flash_mpu_too_slow; } /* now specify all other blocks as not being erased */ while( uccurblock < ucnumblocks ) { ucblock[uccurblock++] = flash_block_not_erased; } } /* step 5: wait for the erase timer bit (dq3) to be set */ while( 1 ) /* timeout!: if, for some reason, the hardware fails then this loop may not exit. use a timer function to implement a timeout from the loop. */ { if( ( flashread( blockoffset[ucblock[0]] ) & 0x08 ) == 0x08 ) break; /* break when device starts the erase cycle */ } /* step 6: follow data toggle flow chart until program/erase controller completes */ if( flashdatatoggle() != flash_success ) { iretval = flash_erase_fail; /* step 7: return to read mode (if an error occurred) */ flashreadreset(); } return iretval; } /******************************************************************************* function: int flashchiperase( unsigned char *ucresults )
AN1198 - application note 18/46 arguments: ucresults is a pointer to an array where the results will be stored. if ucresults == null then no results are stored. otherwise the results are written to the array if an error occurs. the array is left unchanged if the function returns flash_success. the errors written to the array are: flash_block_erased (fdh) if the block erased correctly flash_block_erase_failure (feh) if the block failed to erased return value: on success the function returns flash_success (-1) if a block is protected then the function returns the number of the block and no blocks are erased. if the erase algorithms fails then the function returns flash_erase_fail (-2) if the wrong type of flash is detected then flash_wrong_type (-8) is returned. description: the function can be used to erase the whole flash chip so long as no blocks are protected. if any blocks are protected then nothing is erased. pseudo code: step 1: check for correct flash type step 2: check that all blocks are unprotected step 3: send chip erase command step 4: follow data toggle flow chart until program/erase controller has completed. step 5: check for blocks erased correctly step 6: return to read mode (if an error occurred) *******************************************************************************/ int flashchiperase( unsigned char *ucresults ) { unsigned char uccurblock; /* used to track the current block in a range */ int iretval = flash_success; /* holds return value: optimistic initially! */ /* step 1: check for correct flash type */ if( !(flashautoselect( flash_read_manufacturer ) == manufacturer_st) || !(flashautoselect( flash_read_device_code ) == expected_device ) ) return flash_wrong_type; /* step 2: check that all blocks are unprotected */ for( uccurblock = 0; uccurblock < num_blocks; uccurblock++ ) { if( flashautoselect( (int)uccurblock ) != flash_block_unprotected ) return (int)uccurblock; /* return the first protected block */ } /* step 3: send chip erase command */ flashwrite( 0x0aaal, 0xaa ); flashwrite( 0x0555l, 0x55 ); flashwrite( 0x0aaal, 0x80 ); flashwrite( 0x0aaal, 0xaa ); flashwrite( 0x0555l, 0x55 ); flashwrite( 0x0aaal, 0x10 ); /* step 4: follow data toggle flow chart until program/erase controller has completed */ if( flashdatatoggle() != flash_success ) { iretval = flash_erase_fail; } /* step 5: check for blocks erased correctly */
19/46 AN1198 - application note if( iretval != flash_success && ucresults != null ) { for( uccurblock = 0; uccurblock < num_blocks; uccurblock++ ) { if( flashblockfailederase( uccurblock ) == flash_block_failed_erase ) ucresults[uccurblock] = flash_block_erase_failure; else ucresults[uccurblock] = flash_block_erased; } } /* step 6: return to read mode (if an error occurred) */ if( iretval != flash_success ) flashreadreset(); return iretval; } /******************************************************************************* function: int flashprogram( unsigned long uloff, size_t numbytes, void *array ) arguments: uloff is the byte offset into the flash to be programmed numbytes holds the number of bytes in the array. array is a pointer to the array to be programmed. return value: the function returns the following conditions: flash_success (-1) flash_program_fail (-6) flash_offset_out_of_range (-7) flash_wrong_type (-8) number of the first protected or invalid block on success the function returns flash_success (-1). the function returns flash_program_fail (-6) if a programming failure occurs. if the address range to be programmed exceeds the address range of the flash device the function returns flash_offset_out_of_range (-7) and nothing is programmed. if the wrong type of flash is detected then flash_wrong_type (-8) is returned and nothing is programmed. if part of the address range to be programmed falls within a protected block, the function returns the number of the first protected block encountered and nothing is programmed. description: this function is used to program an array into the flash. it does not erase the flash first and may fail if the block(s) are not erased first. pseudo code: step 1: check for correct flash type step 2: check the offset range is valid step 3: check that the block(s) to be programmed are not protected step 4: while there is more to be programmed step 5: check for changes from 0 to 1 step 6: program the next byte step 7: follow data toggle flow chart until program/erase controller has completed step 8: return to read mode (if an error occurred) step 9: update pointers *******************************************************************************/ int flashprogram( unsigned long uloff, size_t numbytes, void *array )
AN1198 - application note 20/46 { unsigned char *ucarraypointer; /* use an unsigned char to access the array */ unsigned long ullastoff; /* holds the last offset to be programmed */ unsigned char uccurblock; /* range variable to track current block */ /* step 1: check for correct flash type */ if( !(flashautoselect( flash_read_manufacturer ) == manufacturer_st) || !(flashautoselect( flash_read_device_code ) == expected_device ) ) return flash_wrong_type; /* step 2: check the offset and range are valid */ ullastoff = uloff+numbytes-1; if( ullastoff >= flash_size ) return flash_offset_out_of_range; /* step 3: check that the block(s) to be programmed are not protected */ for( uccurblock = 0; uccurblock < num_blocks; uccurblock++ ) { /* if the address range to be programmed ends before this block */ if( blockoffset[uccurblock] > ullastoff ) break; /* then we are done */ /* else if the address range starts beyond this block */ else if( (uccurblock < (num_blocks-1)) && (uloff >= blockoffset[uccurblock+1]) ) continue; /* then skip this block */ /* otherwise if this block is not unprotected */ else if( flashautoselect((int)uccurblock) != flash_block_unprotected ) return (int)uccurblock; /* return first protected block */ } /* step 4: while there is more to be programmed */ ucarraypointer = (unsigned char *)array; while( uloff <= ullastoff ) { /* step 5: check for changes from 0 to 1 */ if( ~flashread( uloff ) & *ucarraypointer ) /* indicate failure as it is not possible to change a 0 to a 1 using a program command. this must be done using an erase command */ return flash_program_fail; /* step 6: program the next byte */ flashwrite( 0x0aaal, 0xaa ); /* 1st cycle */ flashwrite( 0x0555l, 0x55 ); /* 2nd cycle */ flashwrite( 0x0aaal, 0xa0 ); /* program command */ flashwrite( uloff, *ucarraypointer ); /* program value */ /* step 7: follow data toggle flow chart until program/erase controller has completed */ /* see data toggle flow chart of the data sheet */ if( flashdatatoggle() == flash_toggle_fail ) { /* step 8: return to read mode (if an error occurred) */ flashreadreset(); return flash_program_fail; } /* step 9: update pointers */ uloff++; ucarraypointer++;
21/46 AN1198 - application note } return flash_success; } /******************************************************************************* function: static int flashdatatoggle( void ) arguments: none return value: the function returns flash_success if the program/erase controller is successful or flash_toggle_fail if there is a problem. description: the function is used to monitor the program/erase controller during erase or program operations. it returns when the program/erase controller has completed. in the data sheets, the data toggle flow chart shows the operation of the function. pseudo code: step 1: read dq6 (into a byte) step 2: read dq5 and dq6 (into another byte) step 3: if dq6 did not toggle between the two reads then return flash_success step 4: else if dq5 is zero then operation is not yet complete, goto 1 step 5: else (dq5 != 0), read dq6 again step 6: if dq6 did not toggle between the last two reads then return flash_success step 7: else return flash_toggle_fail *******************************************************************************/ static int flashdatatoggle( void ) { unsigned char uc1, uc2; /* hold values read from any address offset within the flash memory */ while( 1 ) /* timeout!: if, for some reason, the hardware fails then this loop may not exit. use a timer function to implement a timeout from the loop. */ { /* step 1: read dq6 (into a byte) */ uc1 = flashread( any_addr ); /* read dq6 from the flash (any address) */ /* step 2: read dq5 and dq6 (into another byte) */ uc2 = flashread( any_addr ); /* read dq5 and dq6 from the flash (any address) */ /* step 3: if dq6 did not toggle between the two reads then return flash_success */ if( (uc1&0x40) == (uc2&0x40) ) /* dq6 == no toggle */ return flash_success; /* step 4: else if dq5 is zero then operation is not yet complete */ if( (uc2&0x20) == 0x00 ) continue; /* step 5: else (dq5 == 1), read dq6 again */ uc1 = flashread( any_addr ); /* read dq6 from the flash (any address) */ /* step 6: if dq6 did not toggle between the last two reads then return flash_success */ if( (uc2&0x40) == (uc1&0x40) ) /* dq6 == no toggle */ return flash_success;
AN1198 - application note 22/46 /* step 7: else return flash_toggle_fail */ else /* dq6 == toggle here means fail */ return flash_toggle_fail; } /* end of while loop */ } #ifndef illustration_only /******************************************************************************* function: static int flashdatapoll( unsigned long uloff, unsigned char ucval ) arguments: uloff should hold a valid offset to be polled. for programming this will be the offset of the byte being programmed. for erasing this can be any offset in the block(s) being erased. ucval should hold the value being programmed. a value of ffh should be used when erasing. return value: the function returns flash_success if the program/erase controller is successful or flash_poll_fail if there is a problem. description: the function is used to monitor the program/erase controller during erase or program operations. it returns when the program/erase controller has completed. in the data sheets, the data toggle flow chart shows the operation of the function. note: this library does not use the data polling flow chart to assess the correct operation of program/erase controller, but uses the data toggle flow chart instead. the flashdatapoll() function is only provided here as an illustration of the data polling flow chart in the data sheet. the code uses the function flashdatatoggle() instead. pseudo code: step 1: read dq5 and dq7 (into a byte) step 2: if dq7 is the same as ucval(bit 7) then return flash_success step 3: else if dq5 is zero then operation is not yet complete, goto 1 step 4: else (dq5 != 0), read dq7 step 5: if dq7 is now the same as ucval(bit 7) then return flash_success step 6: else return flash_poll_fail *******************************************************************************/ static int flashdatapoll( unsigned long uloff, unsigned char ucval ) { unsigned char uc; /* holds value read from valid address */ while( 1 ) /* timeout!: if, for some reason, the hardware fails then this loop may not exit. use a timer function to implement a timeout from the loop. */ { /* step 1: read dq5 and dq7 (into a byte) */ uc = flashread( uloff ); /* read dq5, dq7 at valid addr */ /* step 2: if dq7 is the same as ucval(bit 7) then return flash_success */ if( (uc&0x80) == (ucval&0x80) ) /* dq7 == data */ return flash_success; /* step 3: else if dq5 is zero then operation is not yet complete */ if( (uc&0x20) == 0x00 ) continue; /* step 4: else (dq5 == 1) */ uc = flashread( uloff ); /* read dq7 at valid addr */
23/46 AN1198 - application note /* step 5: if dq7 is now the same as ucval(bit 7) then return flash_success */ if( (uc&0x80) == (ucval&0x80) ) /* dq7 == data */ return flash_success; /* step 6: else return flash_poll_fail */ else /* dq7 != data here means fail */ return flash_poll_fail; } /* end of while loop */ } #endif /* !illustration_only */ /******************************************************************************* function: int flashblockfailederase( unsigned char ucblock ) arguments: ucblock specifies the block to be checked return value: flash_success (-1) if the block erased successfully flash_block_failed_erase (-9) if the block failed to erase description: this function can only be called after an erase operation which has failed the flashdatapoll() function. it must be called before the reset is made. the function reads bit 2 of the status register to determine if the block has erased successfully or not. successfully erased blocks should have dq2 set to 1 following the erase. failed blocks will have dq2 toggle. pseudo code: step 1: read dq2 in the block twice step 2: if they are both the same then return flash_success step 3: else return flash_block_failed_erase *******************************************************************************/ static int flashblockfailederase( unsigned char ucblock ) { unsigned char ucfirstread, ucsecondread; /* two variables used for clarity, optimiser will probably not use any */ /* step 1: read block twice */ ucfirstread = flashread( blockoffset[ucblock] ) & 0x04; ucsecondread = flashread( blockoffset[ucblock] ) & 0x04; /* step 2: if they are the same return flash_success */ if( ucfirstread == ucsecondread ) return flash_success; /* step 3: else return flash_block_failed_erase */ return flash_block_failed_erase; } /******************************************************************************* function: char *flasherrorstr( int ierrnum ); arguments: ierrnum is the error number returned from another flash routine return value: a pointer to a string with the error message description: this function is used to generate a text string describing the error from the flash. call with the return value from another flash routine. pseudo code: step 1: check the error message range. step 2: return the correct string.
AN1198 - application note 24/46 *******************************************************************************/ char *flasherrorstr( int ierrnum ) { static char *str[] = { flash success, flash poll failure, flash too many blocks, mpu is too slow to erase all the blocks, flash block selected is invalid, flash program failure, flash address offset out of range, flash is of wrong type, flash block failed erase, flash is unprotected, flash is protected, flash function not supported, flash vpp invalid, flash erase fail, flash toggle flow chart failure}; /* step 1: check the error message range */ ierrnum = -ierrnum - 1; /* all errors are negative: make +ve & adjust */ if( ierrnum < 0 || ierrnum >= sizeof(str)/sizeof(str[0])) /* check range */ return unknown error\n; /* step 2: return the correct string */ else return str[ierrnum]; } /******************************************************************************* list of errors and return values, explanations and help. ******************************************************************************** return name: flash_success return value: -1 description: this value indicates that the flash command has executed correctly. ******************************************************************************** error name: flash_poll_fail notes: the data polling flow chart, which applies to m29 series flash only, is not used in this library. the function flashdatapoll() is only provided as an illustration of the data polling flow chart. this error condition should not occur when using this library. return value: -2 description: the program/erase controller algorithm has not managed to complete the command operation successfully. this may be because the device is damaged solution: try the command again. if it fails a second time then it is likely that the device will need to be replaced. ******************************************************************************** error name: flash_too_many_blocks notes: applies to m29 series flash only. return value: -3 description: the user has chosen to erase more blocks than the device has. this may be because the array of blocks to erase contains the same block more than once.
25/46 AN1198 - application note solutions: check that the program is trying to erase valid blocks. the device will only have num_blocks blocks (defined at the top of the file). also check that the same block has not been added twice or more to the array. ******************************************************************************** error name: flash_mpu_too_slow notes: applies to m29 series flash only. return value: -4 description: the mpu has not managed to write all of the selected blocks to the device before the timeout period expired. see block erase command section of the data sheet for details. solutions: if this occurs occasionally then it may be because an interrupt is occuring between writing the blocks to be erased. search for dsi! in the code and disable interrupts during the time critical sections. if this error condition always occurs then it may be time for a faster microprocessor, a better optimising c compiler or, worse still, learn assembly. the immediate solution is to only erase one block at a time. disable the test (by #defineing out the code) and always call the function with one block at a time. ******************************************************************************** error name: flash_block_invalid return value: -5 description: a request for an invalid block has been made. valid blocks number from 0 to num_blocks-1. solution: check that the block is in the valid range. ******************************************************************************** error name: flash_program_fail return value: -6 description: the programmed value has not been programmed correctly. solutions: make sure that the block containing the value was erased before programming. try erasing the block and re-programming the value. if it fails again then the device may need to be changed. ******************************************************************************** error name: flash_offset_out_of_range return value: -7 description: the address offset given is out of the range of the device. solution: check that the address offset is in the valid range. ******************************************************************************** error name: flash_wrong_type return value: -8 description: the source code has been used to access the wrong type of flash. solutions: use a different flash chip with the target hardware or contact stmicroelectronics for a different source code library. ******************************************************************************** error name: flash_block_failed_erase return value: -9 description: the previous erase to this block has not managed to successfully erase the block. solution: sadly the flash needs replacing. ******************************************************************************** return name: flash_unprotected notes: applies to some m29 series flash only. this condition should not occur when using this library.
AN1198 - application note 26/46 return value: -10 description: the user has requested to unprotect a flash that is already unprotected or the user has requested to re-protect a flash that has no protected blocks. this is just a warning to the user that their operation did not make any changes and was not necessary. ******************************************************************************** return name: flash_protected notes: this condition should not occur when using this library. return value: -11 description: the user has requested to protect a flash that is already protected. this is just a warning to the user that their operation did not make any changes and was not necessary. ******************************************************************************** return name: flash_function_not_supported notes: this condition should not occur when using this library. return value: -12 description: the user has attempted to make use of functionality not available on this flash device (and thus not provided by the software drivers). this is simply a warning to the user. ******************************************************************************** error name: flash_vpp_invalid notes: applies to m28 series flash only. this error condition should not occur when using this library. return value: -13 description: a program or a block erase has been attempted with the vpp supply voltage outside the allowed ranges. this command had no effect since an invalid vpp has the effect of protecting the whole of the flash device. solution: the (hardware) configuration of vpp will need to be modified to make programming or erasing the device possible. ******************************************************************************** error name: flash_erase_fail return value: -14 description: this indicates that the previous erasure of one block, many blocks or of the whole device has failed. solution: investigate this failure further by attempting to erase each block individually. if erasing a single block still causes failure, then the flash sadly needs replacing. ******************************************************************************* error name: flash_toggle_fail return value: -15 notes: this applies to m29 series flash only. description: the program/erase controller algorithm has not managed to complete the command operation successfully. this may be because the device is damaged. solution: try the command again. if it fails a second time then it is likely that the device will need to be replaced. *******************************************************************************/
27/46 AN1198 - application note /****c1198_16.h*header file for c1198_16.c************************************** filename: c1198_16.h description: header file for c1198_16.c. consult the c file for details copyright (c) 2001 stmicroelectronics. this program is provided as is without warranty of any kind,either expressed or implied, including but not limited to, the implied warranty of merchantability and fitness for a particular purpose. the entire risk as to the quality and performance of the program is with you. should the program prove defective, you assume the cost of all necessary servicing, repair or correction. *******************************************************************************/ /******************************************************************************* commands for the various functions *******************************************************************************/ #define flash_read_manufacturer (-2) #define flash_read_device_code (-1) /******************************************************************************* error conditions and return values. see end of c file for explanations and help *******************************************************************************/ #define flash_block_protected (0x01) #define flash_block_unprotected (0x00) #define flash_block_not_erased (0xff) #define flash_block_erase_failure (0xfe) #define flash_block_erased (0xfd) #define flash_success (-1) #define flash_poll_fail (-2) #define flash_too_many_blocks (-3) #define flash_mpu_too_slow (-4) #define flash_block_invalid (-5) #define flash_program_fail (-6) #define flash_offset_out_of_range (-7) #define flash_wrong_type (-8) #define flash_block_failed_erase (-9) #define flash_erase_fail (-14) #define flash_toggle_fail (-15) /******************************************************************************* function prototypes *******************************************************************************/ extern unsigned int flashread( unsigned long uloff ); extern void flashreadreset( void ); extern int flashautoselect( int ifunc ); extern int flashblockerase( unsigned char ucnumblocks, unsigned char ucblock[]); extern int flashchiperase( unsigned char *ucresults ); extern int flashprogram( unsigned long uloff, size_t numwords, void *array ); extern char *flasherrorstr( int ierrnum );
AN1198 - application note 28/46 /****c1198_16.c*16mb flash memory*********************************************** description: library routines for the m29f160b, m29w160b and m29w160d 16mb (1mb x16) flash memories. 16 bit driver. revision: 1.01 date: 07/02/01 author: tim webster, oxford technical solutions (www.ots.ndirect.co.uk) copyright (c) 2001 stmicroelectronics. this program is provided as is without warranty of any kind, either expressed or implied, including but not limited to, the implied warranty of merchantability and fitness for a particular purpose. the entire risk as to the quality and performance of the program is with you. should the program prove defective, you assume the cost of all necessary servicing, repair or correction. ******************************************************************************** version history. ver. date comments 1.00 29/09/99 initial release of the software. 1.01 07/02/01 added support for m29w160d. ******************************************************************************** this source file provides library c code for using the m29x160b devices. the following devices are supported in the code: m29f160bt m29f160bb m29w160bt m29w160bb m29w160dt m29w160db this file is used to access the devices in 16-bit mode only. a separate file is available for users who wish to access the device in 8 bit mode (c1198_08.c). the following functions are available in this library: flashreadreset() to reset the flash for normal memory access flashautoselect() to get information about the device flashblockerase() to erase one or more blocks flashchiperase() to erase the whole chip flashprogram() to program a word or an array flasherrorstr() to return the error string of an error for further information consult the data sheet and the application note. the application note gives information about how to modify this code for a specific application. the hardware specific functions which need to be modified by the user are: flashwrite() for writing a word to the flash flashread() for reading a word from the flash flashpause() for timing short pauses (in micro seconds)
29/46 AN1198 - application note a list of the error conditions is given at the end of the code. there are no timeouts implemented in the loops in the code. at each point where an infinite loop is implemented a comment /# timeout! #/ has been placed. it is up to the user to implement these to avoid the code hanging instead of timing out. since c does not include a method for disabling interrupts to keep time- critical sections of code from being disabled. the user may wish to disable interrupt during parts of the code to avoid the flash_mpu_too_slow error from occuring if an interrupt occurs at the wrong time. where interrupt should be disabled and re-enabled there is a /# dsi! #/ or /# eni! #/ comment. the source code assumes that the compiler implements the numerical types as unsigned char 8 bits unsigned int 16 bits unsigned long 32 bits additional changes to the code will be necessary if these are not correct. *******************************************************************************/ #include #include c1198_16.h /* header file with global prototypes */ #define use_m29f160bt /******************************************************************************* constants *******************************************************************************/ #define counts_per_microsecond (200) #define manufacturer_st (0x0020) /* manufacturer code */ #define base_addr ((volatile unsigned int*)0x0000) /* base_addr is the base address of the flash, see the functions flashread() and flashwrite(). some applications which require a more complicated flashread() or flashwrite() may not use base_addr */ #define any_addr (0x0000l) /* any address offset within the flash memory will do */ #ifdef use_m29f160bt #define expected_device (0x22cc) /* device code for the m29f160bt */ #endif #ifdef use_m29f160bb #define expected_device (0x224b) /* device code for the m29f160bb */ #endif #ifdef use_m29w160bt #define expected_device (0x22c4) /* device code for the m29w160bt */ #endif #ifdef use_m29w160bb #define expected_device (0x2249) /* device code for the m29w160bb */ #endif
AN1198 - application note 30/46 #ifdef use_m29w160dt #define expected_device (0x22c4) /* device code for the m29w160dt */ #endif #ifdef use_m29w160db #define expected_device (0x2249) /* device code for the m29w160db */ #endif #if defined(use_m29f160bt) | defined(use_m29w160bt) | defined(use_m29w160dt) /* block organisation for top boot block devices */ static const unsigned long blockoffset[] = { 0x00000l, /* start offset of block 0 */ 0x08000l, /* start offset of block 1 */ 0x10000l, /* start offset of block 2 */ 0x18000l, /* start offset of block 3 */ 0x20000l, /* start offset of block 4 */ 0x28000l, /* start offset of block 5 */ 0x30000l, /* start offset of block 6 */ 0x38000l, /* start offset of block 7 */ 0x40000l, /* start offset of block 8 */ 0x48000l, /* start offset of block 9 */ 0x50000l, /* start offset of block 10 */ 0x58000l, /* start offset of block 11 */ 0x60000l, /* start offset of block 12 */ 0x68000l, /* start offset of block 13 */ 0x70000l, /* start offset of block 14 */ 0x78000l, /* start offset of block 15 */ 0x80000l, /* start offset of block 16 */ 0x88000l, /* start offset of block 17 */ 0x90000l, /* start offset of block 18 */ 0x98000l, /* start offset of block 19 */ 0xa0000l, /* start offset of block 20 */ 0xa8000l, /* start offset of block 21 */ 0xb0000l, /* start offset of block 22 */ 0xb8000l, /* start offset of block 23 */ 0xc0000l, /* start offset of block 24 */ 0xc8000l, /* start offset of block 25 */ 0xd0000l, /* start offset of block 26 */ 0xd8000l, /* start offset of block 27 */ 0xe0000l, /* start offset of block 28 */ 0xe8000l, /* start offset of block 29 */ 0xf0000l, /* start offset of block 30 */ 0xf8000l, /* start offset of block 31 */ 0xfc000l, /* start offset of block 32 */ 0xfd000l, /* start offset of block 33 */ 0xfe000l /* start offset of block 34 */ }; #endif /* defined(use_m29f160bt) | defined(use_m29w160bt) | defined(use_m29w160dt) */ #if defined(use_m29f160bb) | defined(use_m29w160bb) | defined(use_m29w160db) /* block organisation for bottom boot block devices */ static const unsigned long blockoffset[] = { 0x00000l, /* start offset of block 0 */ 0x02000l, /* start offset of block 1 */ 0x03000l, /* start offset of block 2 */ 0x04000l, /* start offset of block 3 */
31/46 AN1198 - application note 0x08000l, /* start offset of block 4 */ 0x10000l, /* start offset of block 5 */ 0x18000l, /* start offset of block 6 */ 0x20000l, /* start offset of block 7 */ 0x28000l, /* start offset of block 8 */ 0x30000l, /* start offset of block 9 */ 0x38000l, /* start offset of block 10 */ 0x40000l, /* start offset of block 11 */ 0x48000l, /* start offset of block 12 */ 0x50000l, /* start offset of block 13 */ 0x58000l, /* start offset of block 14 */ 0x60000l, /* start offset of block 15 */ 0x68000l, /* start offset of block 16 */ 0x70000l, /* start offset of block 17 */ 0x78000l, /* start offset of block 18 */ 0x80000l, /* start offset of block 19 */ 0x88000l, /* start offset of block 20 */ 0x90000l, /* start offset of block 21 */ 0x98000l, /* start offset of block 22 */ 0xa0000l, /* start offset of block 23 */ 0xa8000l, /* start offset of block 24 */ 0xb0000l, /* start offset of block 25 */ 0xb8000l, /* start offset of block 26 */ 0xc0000l, /* start offset of block 27 */ 0xc8000l, /* start offset of block 28 */ 0xd0000l, /* start offset of block 29 */ 0xd8000l, /* start offset of block 30 */ 0xe0000l, /* start offset of block 31 */ 0xe8000l, /* start offset of block 32 */ 0xf0000l, /* start offset of block 33 */ 0xf8000l /* start offset of block 34 */ }; #endif /* defined(use_m29f160bb) | defined(use_m29w160bb) | defined(use_m29w160db) */ #define num_blocks (sizeof(blockoffset)/sizeof(blockoffset[0])) #define flash_size (0x100000l) /* 1m */ /******************************************************************************* static prototypes the following functions are only needed in this module. *******************************************************************************/ static unsigned int flashwrite( unsigned long uloff, unsigned int uval ); static void flashpause( unsigned int umicroseconds ); static int flashdatatoggle( void ); static int flashblockfailederase( unsigned char ucblock ); /****************************************************************************** the function flashdatapoll() declared below is not used by this library but is provided as an illustration of the data polling flow chart *******************************************************************************/ #define illustration_only #ifndef illustration_only static int flashdatapoll( unsigned long uloff, unsigned int uval ); #endif /* !illustration_only */
AN1198 - application note 32/46 /******************************************************************************* function: unsigned int flashwrite( unsigned long uloff, unsigned int uval) arguments: uloff is the word offset in the flash to write to uval is the value to be written returns: uval description: this function is used to write a word to the flash. on many microprocessor systems a macro can be used instead, increasing the speed of the flash routines. for example: #define flashwrite( uloff, uval ) ( base_addr[uloff] = (unsigned int) uval ) a function is used here instead to allow the user to expand it if necessary. the function is made to return uval so that it is compatible with the macro. pseudo code: step 1: write uval to the word offset in the flash step 2: return uval *******************************************************************************/ static unsigned int flashwrite( unsigned long uloff, unsigned int uval ) { /* step1, 2: write uval to the word offset in the flash and return it */ return base_addr[uloff] = uval; } /******************************************************************************* function: unsigned int flashread( unsigned long uloff ) arguments: uloff is the word offset into the flash to read from returns: the unsigned int at the word offset description: this function is used to read a word from the flash. on many microprocessor systems a macro can be used instead, increasing the speed of the flash routines. for example: #define flashread( uloff ) ( base_addr[uloff] ) a function is used here instead to allow the user to expand it if necessary. pseudo code: step 1: return the value at word offset uloff *******************************************************************************/ unsigned int flashread( unsigned long uloff ) { /* step 1 return the value at word offset uloff */ return base_addr[uloff]; } /******************************************************************************* function: void flashpause( unsigned int umicroseconds ) arguments: umicroseconds is the length of the pause in microseconds returns: none description: this routine returns after umicroseconds have elapsed. it is used in several parts of the code to generate a pause required for correct operation of the flash part. the routine here works by counting. the user may already have a more suitable routine for timing which can be used. pseudo code: step 1: compute count size for pause.
33/46 AN1198 - application note step 2: count to the required size. *******************************************************************************/ static void flashpause( unsigned int umicroseconds ) { volatile unsigned long ulcountsize; /* step 1: compute the count size */ ulcountsize = (unsigned long)umicroseconds * counts_per_microsecond; /* step 2: count to the required size */ while( ulcountsize > 0 ) /* test to see if finished */ ulcountsize--; /* and count down */ } /******************************************************************************* function: void flashreadreset( void ) arguments: none return value: none description: this function places the flash in the read mode described in the data sheet. in this mode the flash can be read as normal memory. all of the other functions leave the flash in the read mode so this is not strictly necessary. it is provided for completeness. note: a wait of 10us is required if the command is called during a program or erase instruction. this is included here to guarantee correct operation. the functions in this library call this function if they suspect an error during programming or erasing so that the 10us pause is included. otherwise they use the single instruction technique for increased speed. pseudo code: step 1: write command sequence (see commands table of the data sheet) step 2: wait 10us *******************************************************************************/ void flashreadreset( void ) { /* step 1: write command sequence */ flashwrite( 0x0555l, 0x00aa ); /* 1st cycle */ flashwrite( 0x02aal, 0x0055 ); /* 2nd cycle */ flashwrite( any_addr, 0x00f0 ); /* 3rd cycle: write 0x00f0 to any address */ /* step 2: wait 10us */ flashpause( 10 ); } /******************************************************************************* function: int flashautoselect( int ifunc ) arguments: ifunc should be set either to the read signature values or to the block number. the header file defines the values for reading the signature. note: the first block is block 0 return value: when ifunc is >= 0 the function returns flash_block_protected (01h) if the block is protected and flash_block_unprotected (00h) if it is unprotected. see the auto select command in the data sheet for further information. when ifunc is flash_read_manufacturer (-2) the function returns the
AN1198 - application note 34/46 manufacturers code. the manufacturer code for st is 0020h. when ifunc is flash_read_device_code (-1) the function returns the device code. the device codes for the parts are: m29f160bt 22cch m29f160bb 224bh m29w160bt 22c4h m29w160bb 2249h m29w160dt 22c4h m29w160db 2249h when ifunc is invalid the function returns flash_block_invalid (-5) description: this function can be used to read the electronic signature of the device, the manufacturer code or the protection level of a block. pseudo code: step 1: send the auto select command to the device step 2: read the required function from the device. step 3: return the device to read mode. *******************************************************************************/ int flashautoselect( int ifunc ) { int iretval; /* holds the return value */ /* step 1: send the auto select command */ flashwrite( 0x0555l, 0x00aa ); /* 1st cycle */ flashwrite( 0x02aal, 0x0055 ); /* 2nd cycle */ flashwrite( 0x0555l, 0x0090 ); /* 3rd cycle */ /* step 2: read the required function */ if( ifunc == flash_read_manufacturer ) iretval = (int) flashread( 0x0000l ); /* a0 = a1 = 0 */ else if( ifunc == flash_read_device_code ) iretval = (int) flashread( 0x0001l ); /* a0 = 1, a1 = 0 */ else if( (ifunc >= 0) && (ifunc < num_blocks) ) iretval = flashread( blockoffset[ifunc] + 0x0002l ); /* a0 = 0, a1 = 1 */ else iretval = flash_block_invalid; /* step 3: return to read mode */ flashwrite( any_addr, 0x00f0 ); /* use single instruction cycle method */ return iretval; } /******************************************************************************* function: int flashblockerase( unsigned char ucnumblocks, unsigned char ucblock[] ) arguments: ucnumblocks holds the number of blocks in the array ucblock ucblock is an array containing the blocks to be erased. return value: the function returns the following conditions: flash_success (-1) flash_too_many_blocks (-3) flash_mpu_too_slow (-4)
35/46 AN1198 - application note flash_wrong_type (-8) flash_erase_fail (-14) number of the first protected or invalid block the users array, ucblock[] is used to report errors on the specified blocks. if a time-out occurs because the mpu is too slow then the blocks in ucblocks which are not erased are overwritten with flash_block_not_erased (ffh) and the function returns flash_mpu_too_slow. if an error occurs during the erasing of the blocks the function returns flash_erase_fail. if both errors occur then the function will set the ucblock array to flash_block_not_erased for the unerased blocks. it will return flash_erase_fail even though the flash_mpu_too_slow has also occurred. description: this function erases up to ucnumblocks in the flash. the blocks can be listed in any order. the function does not return until the blocks are erased. if any blocks are protected or invalid none of the blocks are erased. during the erase cycle the data toggle flow chart of the data sheet is followed. the polling bit, dq7, is not used. pseudo code: step 1: check for correct flash type step 2: check for protected or invalid blocks step 3: write block erase command step 4: check for time-out blocks step 5: wait for the timer bit to be set. step 6: follow data toggle flow chart until program/erase controller has completed step 7: return to read mode (if an error occurred) *******************************************************************************/ int flashblockerase( unsigned char ucnumblocks, unsigned char ucblock[] ) { unsigned char uccurblock; /* range variable to track current block */ int iretval = flash_success; /* holds return value: optimistic initially! */ unsigned int ufirstread, usecondread; /* used to check toggle bit dq2 */ /* step 1: check for correct flash type */ if( !(flashautoselect( flash_read_manufacturer ) == manufacturer_st) || !(flashautoselect( flash_read_device_code ) == expected_device ) ) return flash_wrong_type; /* step 2: check for protected or invalid blocks. */ if( ucnumblocks > num_blocks ) /* check specified blocks <= num_blocks */ return flash_too_many_blocks; for( uccurblock = 0; uccurblock < ucnumblocks; uccurblock++ ) { /* use flashautoselect to find protected or invalid blocks */ if( flashautoselect((int)ucblock[uccurblock]) != flash_block_unprotected ) return (int)ucblock[uccurblock]; /* return protected/invalid blocks */ } /* step 3: write block erase command */ flashwrite( 0x0555l, 0x00aa ); flashwrite( 0x02aal, 0x0055 ); flashwrite( 0x0555l, 0x0080 ); flashwrite( 0x0555l, 0x00aa ); flashwrite( 0x02aal, 0x0055 );
AN1198 - application note 36/46 /* dsi!: time critical section. additional blocks must be added every 50us */ for( uccurblock = 0; uccurblock < ucnumblocks; uccurblock++ ) { flashwrite( blockoffset[ucblock[uccurblock]], 0x0030 ); /* check for erase timeout period (is bit dq3 set?) */ if( (flashread( blockoffset[ucblock[0]] ) & 0x0008) == 0x0008 ) break; /* cannot set any more blocks due to timeout */ } /* eni! */ /* step 4: check for time-out blocks */ /* if timeout occurred then check if current block is erasing or not */ /* use dq2 of status register, toggle implies block is erasing */ if( uccurblock < ucnumblocks ) { ufirstread = flashread( blockoffset[ucblock[uccurblock]] ) & 0x0004; usecondread = flashread( blockoffset[ucblock[uccurblock]] ) & 0x0004; if( ufirstread != usecondread ) { uccurblock++; /* point to the next block */ } if( uccurblock < ucnumblocks ) { /* indicate that some blocks have been timed out of the erase list */ iretval = flash_mpu_too_slow; } /* now specify all other blocks as not being erased */ while( uccurblock < ucnumblocks ) { ucblock[uccurblock++] = flash_block_not_erased; } } /* step 5: wait for the erase timer bit (dq3) to be set */ while( 1 ) /* timeout!: if, for some reason, the hardware fails then this loop may not exit. use a timer function to implement a timeout from the loop. */ { if( ( flashread( blockoffset[ucblock[0]] ) & 0x0008 ) == 0x0008 ) break; /* break when device starts the erase cycle */ } /* step 6: follow data toggle flow chart until program/erase controller completes */ if( flashdatatoggle() != flash_success ) { iretval = flash_erase_fail; /* step 7: return to read mode (if an error occurred) */ flashreadreset(); } return iretval; } /*******************************************************************************
37/46 AN1198 - application note function: int flashchiperase( unsigned char *ucresults ) arguments: ucresults is a pointer to an array where the results will be stored. if ucresults == null then no results are stored. otherwise the results are written to the array if an error occurs. the array is left unchanged if the function returns flash_success. the errors written to the array are: flash_block_erased (fdh) if the block erased correctly flash_block_erase_failure (feh) if the block failed to erased return value: on success the function returns flash_success (-1) if a block is protected then the function returns the number of the block and no blocks are erased. if the erase algorithms fails then the function returns flash_erase_fail (-2) if the wrong type of flash is detected then flash_wrong_type (-8) is returned. description: the function can be used to erase the whole flash chip so long as no blocks are protected. if any blocks are protected then nothing is erased. pseudo code: step 1: check for correct flash type step 2: check that all blocks are unprotected step 3: send chip erase command step 4: follow data toggle flow chart until program/erase controller has completed. step 5: check for blocks erased correctly step 6: return to read mode (if an error occurred) *******************************************************************************/ int flashchiperase( unsigned char *ucresults ) { unsigned char uccurblock; /* used to track the current block in a range */ int iretval = flash_success; /* holds return value: optimistic initially! */ /* step 1: check for correct flash type */ if( !(flashautoselect( flash_read_manufacturer ) == manufacturer_st) || !(flashautoselect( flash_read_device_code ) == expected_device ) ) return flash_wrong_type; /* step 2: check that all blocks are unprotected */ for( uccurblock = 0; uccurblock < num_blocks; uccurblock++ ) { if( flashautoselect( (int)uccurblock ) != flash_block_unprotected ) return (int)uccurblock; /* return the first protected block */ } /* step 3: send chip erase command */ flashwrite( 0x0555l, 0x00aa ); flashwrite( 0x02aal, 0x0055 ); flashwrite( 0x0555l, 0x0080 ); flashwrite( 0x0555l, 0x00aa ); flashwrite( 0x02aal, 0x0055 ); flashwrite( 0x0555l, 0x0010 ); /* step 4: follow data toggle flow chart until program/erase controller has completed */ if( flashdatatoggle() != flash_success ) { iretval = flash_erase_fail; }
AN1198 - application note 38/46 /* step 5: check for blocks erased correctly */ if( iretval != flash_success && ucresults != null ) { for( uccurblock = 0; uccurblock < num_blocks; uccurblock++ ) { if( flashblockfailederase( uccurblock ) == flash_block_failed_erase ) ucresults[uccurblock] = flash_block_erase_failure; else ucresults[uccurblock] = flash_block_erased; } } /* step 6: return to read mode (if an error occurred) */ if( iretval != flash_success ) flashreadreset(); return iretval; } /******************************************************************************* function: int flashprogram( unsigned long uloff, size_t numwords, void *array ) arguments: uloff is the word offset into the flash to be programmed numwords holds the number of words in the array. array is a pointer to the array to be programmed. return value: the function returns the following conditions: flash_success (-1) flash_program_fail (-6) flash_offset_out_of_range (-7) flash_wrong_type (-8) number of the first protected or invalid block on success the function returns flash_success (-1). the function returns flash_program_fail (-6) if a programming failure occurs. if the address range to be programmed exceeds the address range of the flash device the function returns flash_offset_out_of_range (-7) and nothing is programmed. if the wrong type of flash is detected then flash_wrong_type (-8) is returned and nothing is programmed. if part of the address range to be programmed falls within a protected block, the function returns the number of the first protected block encountered and nothing is programmed. description: this function is used to program an array into the flash. it does not erase the flash first and may fail if the block(s) are not erased first. pseudo code: step 1: check for correct flash type step 2: check the offset range is valid step 3: check that the block(s) to be programmed are not protected step 4: while there is more to be programmed step 5: check for changes from 0 to 1 step 6: program the next word step 7: follow data toggle flow chart until program/erase controller has completed step 8: return to read mode (if an error occurred) step 9: update pointers *******************************************************************************/
39/46 AN1198 - application note int flashprogram( unsigned long uloff, size_t numwords, void *array ) { unsigned int *uarraypointer; /* use an unsigned int to access the array */ unsigned long ullastoff; /* holds the last offset to be programmed */ unsigned char uccurblock; /* range variable to track current block */ /* step 1: check for correct flash type */ if( !(flashautoselect( flash_read_manufacturer ) == manufacturer_st) || !(flashautoselect( flash_read_device_code ) == expected_device ) ) return flash_wrong_type; /* step 2: check the offset and range are valid */ ullastoff = uloff+numwords-1; if( ullastoff >= flash_size ) return flash_offset_out_of_range; /* step 3: check that the block(s) to be programmed are not protected */ for( uccurblock = 0; uccurblock < num_blocks; uccurblock++ ) { /* if the address range to be programmed ends before this block */ if( blockoffset[uccurblock] > ullastoff ) break; /* then we are done */ /* else if the address range starts beyond this block */ else if( (uccurblock < (num_blocks-1)) && (uloff >= blockoffset[uccurblock+1]) ) continue; /* then skip this block */ /* otherwise if this block is not unprotected */ else if( flashautoselect((int)uccurblock) != flash_block_unprotected ) return (int)uccurblock; /* return first protected block */ } /* step 4: while there is more to be programmed */ uarraypointer = (unsigned int *)array; while( uloff <= ullastoff ) { /* step 5: check for changes from 0 to 1 */ if( ~flashread( uloff ) & * uarraypointer ) /* indicate failure as it is not possible to change a 0 to a 1 using a program command. this must be done using an erase command */ return flash_program_fail; /* step 6: program the next word */ flashwrite( 0x0555l, 0x00aa ); /* 1st cycle */ flashwrite( 0x02aal, 0x0055 ); /* 2nd cycle */ flashwrite( 0x0555l, 0x00a0 ); /* program command */ flashwrite( uloff, *uarraypointer ); /* program value */ /* step 7: follow data toggle flow chart until program/erase controller has completed */ /* see data toggle flow chart of the data sheet */ if( flashdatatoggle() == flash_toggle_fail ) { /* step 8: return to read mode (if an error occurred) */ flashreadreset(); return flash_program_fail; } /* step 9: update pointers */ uloff++;
AN1198 - application note 40/46 uarraypointer++; } return flash_success; } /******************************************************************************* function: static int flashdatatoggle( void ) arguments: none return value: the function returns flash_success if the program/erase controller is successful or flash_toggle_fail if there is a problem. description: the function is used to monitor the program/erase controller during erase or program operations. it returns when the program/erase controller has completed. in the data sheets, the data toggle flow chart shows the operation of the function. pseudo code: step 1: read dq6 (into a word) step 2: read dq5 and dq6 (into another word) step 3: if dq6 did not toggle between the two reads then return flash_success step 4: else if dq5 is zero then operation is not yet complete, goto 1 step 5: else (dq5 != 0), read dq6 again step 6: if dq6 did not toggle between the last two reads then return flash_success step 7: else return flash_toggle_fail *******************************************************************************/ static int flashdatatoggle( void ) { unsigned int u1, u2; /* hold values read from any address offset within the flash memory */ while( 1 ) /* timeout!: if, for some reason, the hardware fails then this loop may not exit. use a timer function to implement a timeout from the loop. */ { /* step 1: read dq6 (into a word) */ u1 = flashread( any_addr ); /* read dq6 from the flash (any address) */ /* step 2: read dq5 and dq6 (into another word) */ u2 = flashread( any_addr ); /* read dq5 and dq6 from the flash (any address) */ /* step 3: if dq6 did not toggle between the two reads then return flash_success */ if( (u1&0x0040) == (u2&0x0040) ) /* dq6 == no toggle */ return flash_success; /* step 4: else if dq5 is zero then operation is not yet complete */ if( (u2&0x0020) == 0x0000 ) continue; /* step 5: else (dq5 == 1), read dq6 again */ u1 = flashread( any_addr ); /* read dq6 from the flash (any address) */ /* step 6: if dq6 did not toggle between the last two reads then return flash_success */ if( (u2&0x0040) == (u1&0x0040) ) /* dq6 == no toggle */ return flash_success;
41/46 AN1198 - application note /* step 7: else return flash_toggle_fail */ else /* dq6 == toggle here means fail */ return flash_toggle_fail; } /* end of while loop */ } #ifndef illustration_only /******************************************************************************* function: static int flashdatapoll( unsigned long uloff, unsigned int uval ) arguments: uloff should hold a valid offset to be polled. for programming this will be the offset of the word being programmed. for erasing this can be any offset in the block(s) being erased. uval should hold the value being programmed. a value of ffffh should be used when erasing. return value: the function returns flash_success if the program/erase controller is successful or flash_poll_fail if there is a problem. description: the function is used to monitor the program/erase controller during erase or program operations. it returns when the program/erase controller has completed. in the data sheets, the data toggle flow chart shows the operation of the function. note: this library does not use the data polling flow chart to assess the correct operation of program/erase controller, but uses the data toggle flow chart instead. the flashdatapoll() function is only provided here as an illustration of the data polling flow chart in the data sheet. the code uses the function flashdatatoggle() instead. pseudo code: step 1: read dq5 and dq7 (into a word) step 2: if dq7 is the same as uval(bit 7) then return flash_success step 3: else if dq5 is zero then operation is not yet complete, goto 1 step 4: else (dq5 != 0), read dq7 step 5: if dq7 is now the same as uval(bit 7) then return flash_success step 6: else return flash_poll_fail *******************************************************************************/ static int flashdatapoll( unsigned long uloff, unsigned int uval ) { unsigned int u; /* holds value read from valid address */ while( 1 ) /* timeout!: if, for some reason, the hardware fails then this loop may not exit. use a timer function to implement a timeout from the loop. */ { /* step 1: read dq5 and dq7 (into a word) */ u = flashread( uloff ); /* read dq5, dq7 at valid addr */ /* step 2: if dq7 is the same as uval(bit 7) then return flash_success */ if( (u&0x0080) == (uval&0x0080) ) /* dq7 == data */ return flash_success; /* step 3: else if dq5 is zero then operation is not yet complete */ if( (u&0x0020) == 0x0000 ) continue; /* step 4: else (dq5 == 1) */ u = flashread( uloff ); /* read dq7 at valid addr */
AN1198 - application note 42/46 /* step 5: if dq7 is now the same as uval(bit 7) then return flash_success */ if( (u&0x0080) == (uval&0x0080) ) /* dq7 == data */ return flash_success; /* step 6: else return flash_poll_fail */ else /* dq7 != data here means fail */ return flash_poll_fail; } /* end of while loop */ } #endif /* !illustration_only */ /******************************************************************************* function: int flashblockfailederase( unsigned char ucblock ) arguments: ucblock specifies the block to be checked return value: flash_success (-1) if the block erased successfully flash_block_failed_erase (-9) if the block failed to erase description: this function can only be called after an erase operation which has failed the flashdatapoll() function. it must be called before the reset is made. the function reads bit 2 of the status register to determine if the block has erased successfully or not. successfully erased blocks should have dq2 set to 1 following the erase. failed blocks will have dq2 toggle. pseudo code: step 1: read dq2 in the block twice step 2: if they are both the same then return flash_success step 3: else return flash_block_failed_erase *******************************************************************************/ static int flashblockfailederase( unsigned char ucblock ) { unsigned int ufirstread, usecondread; /* two variables used for clarity, optimiser will probably not use any */ /* step 1: read block twice */ ufirstread = flashread( blockoffset[ucblock] ) & 0x0004; usecondread = flashread( blockoffset[ucblock] ) & 0x0004; /* step 2: if they are the same return flash_success */ if( ufirstread == usecondread ) return flash_success; /* step 3: else return flash_block_failed_erase */ return flash_block_failed_erase; } /******************************************************************************* function: char *flasherrorstr( int ierrnum ); arguments: ierrnum is the error number returned from another flash routine return value: a pointer to a string with the error message description: this function is used to generate a text string describing the error from the flash. call with the return value from another flash routine. pseudo code: step 1: check the error message range.
43/46 AN1198 - application note step 2: return the correct string. *******************************************************************************/ char *flasherrorstr( int ierrnum ) { static char *str[] = { flash success, flash poll failure, flash too many blocks, mpu is too slow to erase all the blocks, flash block selected is invalid, flash program failure, flash address offset out of range, flash is of wrong type, flash block failed erase, flash is unprotected, flash is protected, flash function not supported, flash vpp invalid, flash erase fail, flash toggle flow chart failure}; /* step 1: check the error message range */ ierrnum = -ierrnum - 1; /* all errors are negative: make +ve & adjust */ if( ierrnum < 0 || ierrnum >= sizeof(str)/sizeof(str[0])) /* check range */ return unknown error\n; /* step 2: return the correct string */ else return str[ierrnum]; } /******************************************************************************* list of errors and return values, explanations and help. ******************************************************************************** return name: flash_success return value: -1 description: this value indicates that the flash command has executed correctly. ******************************************************************************** error name: flash_poll_fail notes: the data polling flow chart, which applies to m29 series flash only, is not used in this library. the function flashdatapoll() is only provided as an illustration of the data polling flow chart. this error condition should not occur when using this library. return value: -2 description: the program/erase controller algorithm has not managed to complete the command operation successfully. this may be because the device is damaged solution: try the command again. if it fails a second time then it is likely that the device will need to be replaced. ******************************************************************************** error name: flash_too_many_blocks notes: applies to m29 series flash only. return value: -3 description: the user has chosen to erase more blocks than the device has. this may be because the array of blocks to erase contains the same block
AN1198 - application note 44/46 more than once. solutions: check that the program is trying to erase valid blocks. the device will only have num_blocks blocks (defined at the top of the file). also check that the same block has not been added twice or more to the array. ******************************************************************************** error name: flash_mpu_too_slow notes: applies to m29 series flash only. return value: -4 description: the mpu has not managed to write all of the selected blocks to the device before the timeout period expired. see block erase command section of the data sheet for details. solutions: if this occurs occasionally then it may be because an interrupt is occuring between writing the blocks to be erased. search for dsi! in the code and disable interrupts during the time critical sections. if this error condition always occurs then it may be time for a faster microprocessor, a better optimising c compiler or, worse still, learn assembly. the immediate solution is to only erase one block at a time. disable the test (by #defineing out the code) and always call the function with one block at a time. ******************************************************************************** error name: flash_block_invalid return value: -5 description: a request for an invalid block has been made. valid blocks number from 0 to num_blocks-1. solution: check that the block is in the valid range. ******************************************************************************** error name: flash_program_fail return value: -6 description: the programmed value has not been programmed correctly. solutions: make sure that the block containing the value was erased before programming. try erasing the block and re-programming the value. if it fails again then the device may need to be changed. ******************************************************************************** error name: flash_offset_out_of_range return value: -7 description: the address offset given is out of the range of the device. solution: check that the address offset is in the valid range. ******************************************************************************** error name: flash_wrong_type return value: -8 description: the source code has been used to access the wrong type of flash. solutions: use a different flash chip with the target hardware or contact stmicroelectronics for a different source code library. ******************************************************************************** error name: flash_block_failed_erase return value: -9 description: the previous erase to this block has not managed to successfully erase the block. solution: sadly the flash needs replacing. ******************************************************************************** return name: flash_unprotected notes: applies to some m29 series flash only. this condition should not
45/46 AN1198 - application note occur when using this library. return value: -10 description: the user has requested to unprotect a flash that is already unprotected or the user has requested to re-protect a flash that has no protected blocks. this is just a warning to the user that their operation did not make any changes and was not necessary. ******************************************************************************** return name: flash_protected notes: this condition should not occur when using this library. return value: -11 description: the user has requested to protect a flash that is already protected. this is just a warning to the user that their operation did not make any changes and was not necessary. ******************************************************************************** return name: flash_function_not_supported notes: this condition should not occur when using this library. return value: -12 description: the user has attempted to make use of functionality not available on this flash device (and thus not provided by the software drivers). this is simply a warning to the user. ******************************************************************************** error name: flash_vpp_invalid notes: applies to m28 series flash only. this error condition should not occur when using this library. return value: -13 description: a program or a block erase has been attempted with the vpp supply voltage outside the allowed ranges. this command had no effect since an invalid vpp has the effect of protecting the whole of the flash device. solution: the (hardware) configuration of vpp will need to be modified to make programming or erasing the device possible. ******************************************************************************** error name: flash_erase_fail return value: -14 description: this indicates that the previous erasure of one block, many blocks or of the whole device has failed. solution: investigate this failure further by attempting to erase each block individually. if erasing a single block still causes failure, then the flash sadly needs replacing. ******************************************************************************* error name: flash_toggle_fail return value: -15 notes: this applies to m29 series flash only. description: the program/erase controller algorithm has not managed to complete the command operation successfully. this may be because the device is damaged. solution: try the command again. if it fails a second time then it is likely that the device will need to be replaced. *******************************************************************************/
AN1198 - application note 46/46 if you have any questions or suggestion concerning the matters raised in this document please send them to the following electronic mail address: ask.memory@st.com (for general enquiries) please remember to include your name, company, location, telephone number and fax number. information furnished is believed to be accurate and reliable. however, stmicroelectronics assumes no responsibility for the co nsequences of use of such information nor for any infringement of patents or other rights of third parties which may result from its use. no license is granted by implication or otherwise under any patent or patent rights of stmicroelectronics. specifications mentioned in this publicati on are subject to change without notice. this publication supersedes and replaces all information previously supplied. stmicroelectronics prod ucts are not authorized for use as critical components in life support devices or systems without express written approval of stmicroelectro nics. the st logo is registered trademark of stmicroelectronics all other names are the property of their respective owners ? 2001 stmicroelectronics - all rights reserved stmicroelectronics group of companies australia - brazil - china - finland - france - germany - hong kong - india - italy - japan - malaysia - malta - morocco - singapore - spain - sweden - switzerland - united kingdom - u.s.a. www.st.com


▲Up To Search▲   

 
Price & Availability of AN1198

All Rights Reserved © IC-ON-LINE 2003 - 2022  

[Add Bookmark] [Contact Us] [Link exchange] [Privacy policy]
Mirror Sites :  [www.datasheet.hk]   [www.maxim4u.com]  [www.ic-on-line.cn] [www.ic-on-line.com] [www.ic-on-line.net] [www.alldatasheet.com.cn] [www.gdcy.com]  [www.gdcy.net]


 . . . . .
  We use cookies to deliver the best possible web experience and assist with our advertising efforts. By continuing to use this site, you consent to the use of cookies. For more information on cookies, please take a look at our Privacy Policy. X